package org.study.module.ldap;

import java.util.ArrayList;
import java.util.List;

public class LDAPShell {

    public static List<String> command() {
        List<String> shell = new ArrayList<>();
        shell.add("#安装 OpenLDAP 相关包");
        shell.add("sudo yum install -y openldap openldap-servers openldap-clients");
        shell.add("# 复制默认数据库配置模板，并修改用户组");
        shell.add("sudo cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG");
        shell.add("sudo chown -R ldap:ldap /var/lib/ldap/");
        shell.add("");
        return shell;
    }

    /**
     * 导入用户,用户组，基本结构
     *
     * @param realm         域名
     * @param adminPassword admin用户的密码
     * @param userFile      需要导入用户的文件
     */
    public static String loadFile(String realm, String adminPassword, String userFile) {
        String[] realms = realmSplit(realm);
        return "ldapadd -x -D \"cn=admin,dc=" + realms[0] + ",dc=" + realms[1] + "\" -w " + adminPassword + " -f " + userFile;
    }

    public static String[] realmSplit(String realm) {
        if (realm == null || realm.isEmpty()) {
            throw new RuntimeException("REALM 名称不能为空！需要的格式如：hadoop.com");
        }
        String[] splits = realm.toLowerCase().split(".");
        if (splits.length != 2) {
            throw new RuntimeException("REALM 名称异常！" + realm + "，需要的格式如：hadoop.com");
        }
        return splits;
    }

    /**
     * 执行配置文件,
     *
     * @param file 文件地址
     */
    public static String executeFile(String file) {
        return "ldapmodify -Y EXTERNAL  -H ldapi:/// -f " + file;
    }

    /**
     * 配置基本域结构，写入的文件名称后缀.ldip。cat > /tmp/ldap_domain.ldif << EOF
     * LDAP中：root的用户为admin
     *
     * @param sshaPwd root的ssha之后的密码
     * @param realm   域名
     */
    public static List<String> addDomain(String sshaPwd, String realm) {
        List<String> configs = new ArrayList<>();
        String[] realms = realmSplit(realm);
        configs.add("#LDAP 监控配置");
        configs.add("dn: olcDatabase={1}monitor,cn=config");
        configs.add("changetype: modify");
        configs.add("replace: olcAccess");
        //其中admin和下面olcRootDN中的cn的值是一致的。这里默认admin
        configs.add("olcAccess: {0}to * by dn.base=\"gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth\" read by dn.base=\"cn=admin,dc="+realms[0]+",dc="+realms[1]+"\" read by * none\n");
        configs.add("# ldap数据库前缀");
        configs.add("dn: olcDatabase={2}hdb,cn=config");
        configs.add("changetype: modify");
        configs.add("replace: olcSuffix");
        configs.add("olcSuffix: dc=" + realms[0] + ",dc=" + realms[1]);
        configs.add("# LDAP上超级管理员的DN");
        configs.add("dn: olcDatabase={2}hdb,cn=config");
        configs.add("changetype: modify");
        configs.add("replace: olcRootDN");
        configs.add("olcRootDN: cn=admin,dc=" + realms[0] + ",dc=" + realms[1]);
        configs.add("# RootDN的密码");
        configs.add("dn: olcDatabase={2}hdb,cn=config");
        configs.add("changetype: modify");
        configs.add("replace: olcRootPW");
        configs.add("olcRootPW: " + sshaPwd);
        configs.add("# 添加访问控制");
        configs.add("dn: olcDatabase={2}hdb,cn=config");
        configs.add("changetype: modify");
        configs.add("add: olcAccess");
        configs.add("olcAccess: {0}to attrs=userPassword,shadowLastChange by dn=\"cn=admin,dc="+realms[0]+",dc="+realms[1]+"\" write by anonymous auth by self write by * none");
        configs.add("olcAccess: {1}to dn.base=\"\" by * read");
        configs.add("olcAccess: {2}to * by dn=\"cn=admin,dc="+realms[0]+",dc="+realms[1]+"\" write by * read");
        return configs;
    }

    public static List<String> add(String sshaPwd,String realm){
        List<String> configs = new ArrayList<>();
        String[] realms = realmSplit(realm);
        configs.add("#设置域");
        configs.add("dn: dc="+realms[0]+",dc="+realms[1]);
        configs.add("objectClass: top");
        configs.add("objectClass: domain");
        configs.add("dc: "+realms[0]);
        configs.add("#LDAP超级账户");
        configs.add("dn: cn=admin,dc="+realms[0]+",dc="+realms[1]);
        configs.add("objectClass: simpleSecurityObject");
        configs.add("objectClass: organizationalRole");
        configs.add("cn: admin");
        configs.add("userPassword: "+sshaPwd);
        configs.add("description: LDAP Administrator");
        configs.add("#LDAP用户的目录");
        configs.add("dn: ou=users,dc="+realms[0]+",dc="+realms[1]);
        configs.add("objectClass: top");
        configs.add("objectClass: organizationalUnit");
        configs.add("ou: users");
        configs.add("#LDAP组的目录");
        configs.add("dn: ou=groups,dc="+realms[0]+",dc="+realms[1]);
        configs.add("objectClass: top");
        configs.add("objectClass: organizationalUnit");
        configs.add("ou: groups");
        return configs;
    }


    public static String toSSHA(String pwd) {
        return "slappasswd -h {ssha} -s " + pwd;
    }

    /**
     * 添加用户和用户组
     *
     * @param group
     * @param user
     * @param realm 域名
     * @return
     */
    public static List<String> addUserAndGroup(String group, String user, String realm) {
        List<String> configs = new ArrayList<>();
        String[] realms = realmSplit(realm);
        configs.add("# 组信息");
        configs.add("dn: cn=" + group + ",ou=Group,dc=" + realms[0] + ",dc="+realms[1]);
        configs.add("objectClass: posixGroup");
        configs.add("objectClass: top");
        configs.add("cn: " + group);
        configs.add("gidNumber: 3001");
        configs.add("memberUid: " + group);
        configs.add("");
        configs.add("dn: uid=" + user + ",ou=People,dc=" + realms[0] + ",dc="+realms[1]);
        configs.add("uid: " + user);
        configs.add("cn: " + group);
        configs.add("objectClass: account");
        configs.add("objectClass: posixAccount");
        configs.add("objectClass: top");
        //# 密码（实际环境建议使用加密值）
        configs.add("userPassword: " + user);
        configs.add("loginShell: /bin/bash");
        configs.add("uidNumber: 3001");
        configs.add("gidNumber: 3001");
        configs.add("homeDirectory: /home/" + user);
        return configs;
    }
}
